package com.kye.express.business.popularity;

import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.text.TextUtils;

import com.kye.express.contract.base.BasePresenter;
import com.kye.express.contract.base.view.ErrorView;
import com.kye.express.contract.base.view.IView;
import com.kye.express.contract.base.view.LoadingView;
import com.kye.model.OpenApiResultObserver;
import com.kye.model.UserSession;
import com.kye.model.base.RetrofitManager;
import com.kye.model.bean.OpenApiResult;
import com.kye.model.bean.popularity.PhoneNumber;
import com.kye.model.bean.popularity.request.RequestAddContacts;
import com.kye.model.bean.popularity.request.RequestGetContacts;
import com.kye.model.bean.user.User;
import com.kye.model.content_resolver.RxContentResolver;
import com.kye.model.service.PopularityService;

import org.reactivestreams.Publisher;

import java.util.Arrays;
import java.util.List;

import io.reactivex.Flowable;
import io.reactivex.FlowableTransformer;
import io.reactivex.Single;
import io.reactivex.SingleSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.BiFunction;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;

public interface PopularityContract {
    interface PopularityView extends IView, LoadingView, ErrorView {

        void onSuccess();
    }

    class PopularityPresenter extends BasePresenter<PopularityView> {
        private static final String[] PHONES_PROJECTION = new String[]{
                ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                ContactsContract.CommonDataKinds.Phone.NUMBER
        };

        public void uploadContacts(final ContentResolver contentResolver) {
            final List<Flowable<PhoneNumber>> flowableContacts = Arrays.asList(
                    RxContentResolver.getFlowable(contentResolver, ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PHONES_PROJECTION, null, null, null, null)
                            .compose(getAddressBookFlowableTransformer()),
                    RxContentResolver.getFlowable(contentResolver, Uri.parse("content://icc/adn"), PHONES_PROJECTION, null, null, null, null)
                            .compose(getAddressBookFlowableTransformer()),
                    RxContentResolver.getFlowable(contentResolver, Uri.parse("content://icc/adn/subid/0"), PHONES_PROJECTION, null, null, null, null)
                            .compose(getAddressBookFlowableTransformer()),
                    RxContentResolver.getFlowable(contentResolver, Uri.parse("content://icc/adn/subid/1"), PHONES_PROJECTION, null, null, null, null)
                            .compose(getAddressBookFlowableTransformer()),
                    RxContentResolver.getFlowable(contentResolver, Uri.parse("content://icc/pbr/subId/0"), PHONES_PROJECTION, null, null, null, null)
                            .compose(getAddressBookFlowableTransformer()),
                    RxContentResolver.getFlowable(contentResolver, Uri.parse("content://icc/pbr/subId/1"), PHONES_PROJECTION, null, null, null, null)
                            .compose(getAddressBookFlowableTransformer())
            );

            Single.zip(UserSession.getInstance()
                            .getUserForRx()
                            .firstOrError()
                            .flatMap(new Function<User, Single<OpenApiResult<List<PhoneNumber>>>>() {
                                @Override
                                public Single<OpenApiResult<List<PhoneNumber>>> apply(User user) throws Exception {
                                    return RetrofitManager.getInstance()
                                            .createOpenApiService(PopularityService.class)
                                            .getContacts(new RequestGetContacts(user.getPhone()));
                                }
                            })
                            .map(new Function<OpenApiResult<List<PhoneNumber>>, List<PhoneNumber>>() {
                                @Override
                                public List<PhoneNumber> apply(OpenApiResult<List<PhoneNumber>> listOpenApiResult) throws Exception {
                                    return listOpenApiResult.getData();
                                }
                            }),
                    Flowable.merge(flowableContacts)
                            .distinct(new Function<PhoneNumber, String>() {
                                @Override
                                public String apply(PhoneNumber phoneNumber) throws Exception {
                                    return phoneNumber.getMobileNo();
                                }
                            })
                            .toList(),
                    new BiFunction<List<PhoneNumber>, List<PhoneNumber>, List<PhoneNumber>>() {
                        @Override
                        public List<PhoneNumber> apply(List<PhoneNumber> remote, List<PhoneNumber> local) throws Exception {
                            local.removeAll(remote);
                            return local;
                        }
                    }
            )
                    .flatMap(new Function<List<PhoneNumber>, SingleSource<OpenApiResult<Object>>>() {
                        @Override
                        public SingleSource<OpenApiResult<Object>> apply(List<PhoneNumber> phoneNumbers) throws Exception {
                            return RetrofitManager.getInstance()
                                    .createOpenApiService(PopularityService.class)
                                    .addContacts(new RequestAddContacts(UserSession.getInstance().getUser().getPhone(), phoneNumbers));
                        }
                    })
                    .compose(getView().<OpenApiResult<Object>>bindToLifecycleDestroy())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new OpenApiResultObserver<Object>() {
                        @Override
                        public void onLoading(Disposable d) {
                            getView().onLoading();
                        }

                        @Override
                        public void onSuccess(OpenApiResult<Object> result, Object o) {
                            getView().onSuccess();
                        }

                        @Override
                        public void onApiError(OpenApiResult<Object> result, int code, String msg) {
                            getView().onError(msg);
                        }

                        @Override
                        public void onOtherError(Throwable e) {
                            getView().onError();
                        }

                        @Override
                        public void onLoaded() {
                            getView().onLoaded();
                        }
                    });
        }

        @NonNull
        private FlowableTransformer<Cursor, PhoneNumber> getAddressBookFlowableTransformer() {
            return new FlowableTransformer<Cursor, PhoneNumber>() {
                @Override
                public Publisher<PhoneNumber> apply(Flowable<Cursor> upstream) {
                    return upstream.map(new Function<Cursor, PhoneNumber>() {
                        @Override
                        public PhoneNumber apply(Cursor cursor) throws Exception {
                            return new PhoneNumber(cursor.getString(1), cursor.getString(0));
                        }
                    })
                            .filter(new Predicate<PhoneNumber>() {
                                @Override
                                public boolean test(PhoneNumber phoneNumber) throws Exception {
                                    return !TextUtils.isEmpty(phoneNumber.getMobileNo());
                                }
                            })
                            .onErrorResumeNext(new Function<Throwable, Publisher<? extends PhoneNumber>>() {
                                @Override
                                public Publisher<? extends PhoneNumber> apply(Throwable throwable) throws Exception {
                                    return Flowable.empty();
                                }
                            });
                }
            };
        }
    }
}
